#include "xvideo_view.h"
#include "xsdl.h"
#include <chrono>
#include <stdint.h>
#include <thread>
extern "C"
{
#include "libavutil/frame.h"
}
#pragma comment(lib, "avutil.lib")
using namespace std;

///////////////////////////////////////////
///// 视频渲染接口类
///// 1.隐藏SDL实现
///// 2.渲染方案可替代
///// 3.线程安全
void MSleep(uint64_t ms)
{
    this_thread::sleep_for(chrono::milliseconds(ms));
}

long long NowMs()
{
    auto now = chrono::high_resolution_clock::now();
    return chrono::duration_cast<chrono::milliseconds>(now.time_since_epoch()).count();
}

AVFrame *XVideoView::Read()
{
  if (width_ <= 0 || height_ <= 0 || !ifs_)
    return nullptr;
  // 是否已经申请了AVFrame，如果已经申请并且参数不一致，那么因该释放空间便重新申请
  if (frame_)
  {
    if (frame_->width != width_ || frame_->height != height_ || frame_->format != fmt_)
    {
      // 先把数据引用计数减一，然后释放frame的控件，最后把frame_指向nullptr
      av_frame_free(&frame_);
    }
  }
  if (!frame_) // 第一次申请 或 被释放掉了
  {
    frame_ = av_frame_alloc();
    frame_->width = width_;
    frame_->height = height_;
    frame_->format = fmt_;
    frame_->linesize[0] = width_ * 4;
    if (frame_->format == AV_PIX_FMT_YUV420P)
    {
      frame_->linesize[0] = width_;
      frame_->linesize[1] = frame_->linesize[2] = width_ / 2;
    }
    int ret = av_frame_get_buffer(frame_, 32);
    if (ret < 0)
    {
      char err[1024] = {0};
      av_strerror(ret, err, sizeof(err) - 1);
      av_log(NULL, AV_LOG_ERROR, "av_frame_get_buffer error: %s\n", err);
      av_frame_free(&frame_);
    }
  }
  if (!frame_)
    return nullptr;
  // 读取一帧数据
  if (frame_->format == AV_PIX_FMT_YUV420P)
  {
    ifs_.read((char *)frame_->data[0], frame_->linesize[0] * frame_->height);     // Y
    ifs_.read((char *)frame_->data[1], frame_->linesize[1] * frame_->height / 2); // U
    ifs_.read((char *)frame_->data[2], frame_->linesize[2] * frame_->height / 2); // V
  }
  else
  {
    ifs_.read((char *)frame_->data[0], frame_->linesize[0] * frame_->height);
  }
  if (ifs_.gcount() <= 0)
  {
    return nullptr;
  }
  return frame_;
}
bool XVideoView::Open(std::string filepath)
{
  if (ifs_.is_open())
  {
    ifs_.close();
  }
  ifs_.open(filepath, std::ios::binary);
  return ifs_.is_open();
}
XVideoView *XVideoView::Create(RenderType type)
{
  switch (type)
  {
  case XVideoView::SDL:
    return new XSDL();
    break;
    // case RenderType::XV: return new XVideoView();break;
    // case RenderType::QT: return new SdlQtRGB();break;
  }
  return nullptr;
}

bool XVideoView::DrawFrame(AVFrame *frame)
{
  if (!frame || !frame->data[0]) return false;
  count_++;
  if (beg_ms_ <= 0)
  {
    beg_ms_ = clock();
  }
  // 计算帧率
  else if ((clock() - beg_ms_) / (CLOCKS_PER_SEC / 1000) >= 1000)
  {
    render_fps_ = count_;
	count_ = 0;
    beg_ms_ = clock();
  }
  switch (frame->format)
  {
  case AV_PIX_FMT_YUV420P:
    return Draw(frame->data[0], frame->linesize[0],  // Y
                frame->data[1], frame->linesize[1],  // U
                frame->data[2], frame->linesize[2]); // V
  case AV_PIX_FMT_BGRA:
  case AV_PIX_FMT_ARGB:
  case AV_PIX_FMT_RGBA:
    return Draw(frame->data[0], frame->linesize[0]);
  default:
    break;
  }
  return false;
}